var maxValue = 1000000000;
var p3366Gifts = [
    {'min':1, 'max':5, 'awards':[['user', 'gold', 50000],['material', 38, 3]]},
    {'min':6, 'max':10, 'awards':[['user', 'gold', 80000],['material', 38, 5]]},
    {'min':11, 'max':15, 'awards':[['user', 'gold', 120000],['material', 48, 1]]},
    {'min':16, 'max':20, 'awards':[['user', 'gold', 180000],['material', 48, 2]]},
    {'min':21, 'max':25, 'awards':[['user', 'gold', 250000],['material', 48, 3]]},
    {'min':26, 'max':200, 'awards':[['user', 'gold', 300000],['material', 48, 4]]},
];


var yellowDailyReward = {
    1 : {food: 500, gold:50000},
    2 : {food: 500, gold:60000},
    3 : {food: 500, gold:80000},
    4 : {food: 1000, gold:100000},
    5 : {food: 1000, gold:120000},
    6 : {food: 1500, gold:140000},
    7 : {food: 1500, gold:160000},
    8 : {food: 2000, gold:180000},
};

var blueLevelGoldReward = {
    1 : 100000,
    2 : 150000,
    3 : 200000,
    4 : 400000,
    5 : 600000,
    6 : 1000000,
    7 : 2000000,
    8 : 5000000
}

function doChangeRoleGrouth(player, role, value) {
    var roleId = role.id;
    var roleConf = gConfRole[roleId];
    var grouth = value;
    var needGrouthBreak = (role.grouth_break || 0);
    var needFullSkill = 0;
    
    var grouthBreakConf = gConfGrouthBreak[needGrouthBreak];
    while (grouth > grouthBreakConf.Grouth) {
        if (!gConfGrouthBreak[needGrouthBreak + 1]) {
            grouth = grouthBreakConf.Grouth;  
            break;
        }

        needFullSkill = Math.max(needFullSkill, +grouthBreakConf.FullSkill);
        needGrouthBreak += 1;
        grouthBreakConf = gConfGrouthBreak[needGrouthBreak];
    }

    var fullSkillCount = 0;
    for (var skill = 1; skill <=5; ++skill) {
        if ((role.skill_levels[skill] || 0) >= 10) {
            fullSkillCount += 1;
        }
    }

    if (fullSkillCount < needFullSkill) {
        for (var skill = 1; skill <= needFullSkill; ++skill) {
            role.skill_levels[skill] = 10;
            player.markDirty(util.format('role.%d.skill_levels.%d', roleId, skill));
        }
    }
    
    var soldierLevel = role.soldier_level || 1;
    var grouthConf = gConfGrouth[gConfRole[roleId].Quantity];
    for (var level = 2; ; ++level) {
        var levelMinGrouth = grouthConf['Min'+level];
        if (!levelMinGrouth || grouth < levelMinGrouth) {
            break;
        }

        soldierLevel = level;
    }

    role.grouth = grouth;
    role.grouth_break = needGrouthBreak;
    role.soldier_level = soldierLevel;

    var soldierLevel = 1;
    var grouthConf = gConfGrouth[roleConf.Quantity];
    for (var level = 2; level <=5; ++level) {
        if (grouth >= grouthConf['Min'+level]) {
            soldierLevel = level;
        }
    }

    role.soldier_level = soldierLevel;

    player.doTask('UpgradeSkill', 'all');

    player.markDirty(util.format('role.%d.grouth', roleId));
    player.markDirty(util.format('role.%d.grouth_break', roleId));
    player.markDirty(util.format('role.%d.soldier_level', roleId));
    player.roleDirty = true;
}

function doChangeRoleSoul(player, role, value) {
    var soul = value;
    var oldSoulBreak = (role.soul_break || 0);
    var needSoulBreak = oldSoulBreak;

    while (soul > gConfSoulBreak[needSoulBreak].Soul) {
        if (!gConfSoulBreak[needSoulBreak + 1]) {
            soul = gConfSoulBreak[needSoulBreak].Soul;
            break;
        }
        needSoulBreak += 1;
    }

    role.soul = soul;
    role.soul_break = needSoulBreak;
    player.doTask('UpgradeSoulLevel', 'all');
    
    player.markDirty(util.format('role.%d.soul', role.id));
    player.markDirty(util.format('role.%d.soul_break', role.id));
    player.roleDirty = true;

    if (needSoulBreak > oldSoulBreak) {
        var needGrouth = gConfSoulBreak[needSoulBreak - 1].Grouth;
        var needGod = gConfSoulBreak[needSoulBreak - 1].God;

        if (needGrouth > (role.grouth || 0)) {
            doChangeRoleGrouth(player, role, needGrouth);
        }

        if (needGod > (role.god || 0)) {
            doChangeRoleGod(player, role, needGod);
        }
    }
}

function doChangeRoleGod(player, role, value) {
    if (value <= 0 || !gConfGodLevel[value]) {
        return;
    }

    var roleId = role.id;
    var god = value;
    var oldGod = role.god || 0;
    var roleConf = gConfRole[roleId];

    if (god > oldGod) {
        role.god = god;
        player.markDirty(util.format('role.%d.god', roleId));
        player.roleDirty = true;

        if (!oldGod) {
            // 第一次觉醒时,增加坐骑
            var horseUniqId = player.addHorse(gConfGlobal.InitalHorseId);
            player.addRoleRide(roleId, horseUniqId);

            // 增加初始羽翼
            player.addRoleWing(roleId, gConfGlobal.InitialWingLevel);
        }

        for (var i = oldGod + 1; i <= god; ++i) {
            if (gConfGodLevel[i].SpSkill) {
                var spSkillFlag = +(gConfGodLevel[i].SpSkill);
                if (1 == spSkillFlag && roleConf.SpecialSkill) {
                    role.skill_levels[roleConf.SpecialSkill] = 1;
                    player.markDirty(util.format('role.%d.skill_levels', roleId));
                }  else if (2 == spSkillFlag && roleConf.SpecialSkill2) {
                    role.skill_levels[roleConf.SpecialSkill2] = 1;
                    player.markDirty(util.format('role.%d.skill_levels', roleId));
                }
            }
        }
    
        var needGrouth = gConfGodLevel[god - 1].Grouth;
        var needSoul = gConfGodLevel[god - 1].Soul;

        if (needGrouth > (role.grouth || 0)) {
            doChangeRoleGrouth(player, role, needGrouth);
        }

        if (needSoul > (role.soul || 0)) {
            doChangeRoleSoul(player, role, needSoul);
        }
    }
}

function doChangePlayerLevel(player, newLevel) {
    if (!gConfLevel[newLevel]) {
        return false;
    } 
    
    var user = player.user;
    user.status.xp = gConfLevel[newLevel-1].Xp;
    user.status.level = newLevel;
    player.markDirty('status.xp');
    player.markDirty('status.level');
    return true;
}


exports.gm = function(player, req, resp, onHandled) {
    
    do {
        if( req.args.key != config.GMAuth ) {
            resp.code = 1; resp.desc = 'invalid key'; break;
        }

        var method = req.args.method;
        var user = player.user;
        var uid = player.uid;
        if (method == "custom_status") {
            /*
            domain:operation:key=value
                demain:可选的,game,cloud_rank,champsbattle
                operation:可选的,set,gset,fun
                    为set时,表示修改玩家属性,key为属性名称描述,value为值
                    为gset时,表示修改全局属性,key为属性名称描述,value为值
                    为fun时,表示调用logic接口,key为接口名称描述,value为接口额外参数
            */
            var desc = req.args.value;
            var kv = desc.split("=");
            if (kv.length != 2) {
                resp.code = 1; resp.desc = 'custom desc invalid'; break;
            }

            var value = kv[1];
            var keyName = kv[0];

            var domain = 'game';
            var operation = 'set';
            var nameDomains = keyName.split(":");
            if (2 == nameDomains.length) {
                domain = nameDomains[0];
                keyName = nameDomains[1];
            } else if (3 == nameDomains.length) {
                domain = nameDomains[0];
                operation = nameDomains[1];
                keyName = nameDomains[2];
            }

            var names = keyName.split(".");
            if (names.length < 1) {
                resp.code = 1; resp.desc = 'custom name invalid'; break;
            }
            
            if ('game' == domain) {
                if (!isNaN(value)) {
                    value = +value;
                } else {
                    try {
                        value = JSON.parse(value);
                    } catch (e) {
                        resp.code = 1; resp.desc = e.message; break;
                    }
                }

                if (operation == 'set') {
                    var key = names[names.length-1];
                    var obj = user;
                    for (var i = 0; i < names.length-1; ++i) {
                        obj = obj[names[i]];

                        if (typeof(obj) != 'object') {
                            obj = null;
                        }

                        if (null == obj) break;
                    }

                    if (null == obj) {
                        resp.code = 1; resp.desc = 'custom name not exist'; break;
                    }

                    obj[key] = value;
                    player.markDirty(keyName);
                } else if (operation == 'fun') {
                    var handler = getObjectNamesValue(logic, names);
                    if (!handler) {
                        resp.code = 1; resp.desc = 'custom function name invalid'; break;
                    }

                    for (var k in value) {
                        req.args[k] = value[k];
                    }
                    handler(player, req, resp, function() {
                        onHandled();
                    });
                    return;
                }
            } else if ('cloud_rank' == domain) {
                var worldReq = {
                    mod : 'gm',
                    act : 'custom',
                    args : {
                        'name' : keyName,
                        'value' : value,
                        'operation': operation,
                    },
                }
                player.requestCloudRank(worldReq, resp, function() {
                    onHandled();
                });
                return;
            } else if ('champsbattle' == domain) {
                var worldReq = {
                    mod : 'gm',
                    act : 'custom',
                    args : {
                        'name' : keyName,
                        'value' : value,
                        'operation': operation,
                    },
                }
                player.requestChampsBattle(worldReq, resp, function() {
                    onHandled();
                });
                return;
            } else {
                resp.code = 1; resp.desc = 'unknown domain'; break;
            }
        } else if( method == 'status' ) {
            var type = req.args.type;

            if (user.status.hasOwnProperty(type)) {
                if ('cash' == type) {
                    resp.code = 1; resp.desc = 'status type forbidden'; break;
                }

                if (isNaN(req.args.value)) {
                    resp.code = 1; resp.desc = 'value invalid'; break;
                }

                var value = +req.args.value;
                if (value > maxValue || value < 0) {
                    resp.code = 1; resp.desc = 'value wrong'; break;
                }

                var way = req.args.way;
                if ('add' == way) {
                    var nowValue = (user.status[type] || 0) + value;
                    if ('xp' == type) {
                        player.addXp(value);
                    } else if ('level' == type) {
                        if (!doChangePlayerLevel(player, nowValue)) {
                            resp.code = 1; resp.desc = 'level wrong'; break;
                        }
                    } else {
                        user.status[type] = nowValue;
                        player.addStatusAwards([['user', type, value]]);

                    }
                    player.markDirty('status.'+type); 
                } else if ('set' == way) {
                    var oldValue = user.status[type] || 0;
                    if ('xp' == type) {
                        resp.code = 1; resp.desc = "can't set xp"; break;
                    } else if ('level' == type) {
                        if (!gConfLevel[value]) {
                            resp.code = 1; resp.desc = 'level wrong'; break;
                        } 
                        user.status.level = value;
                        user.status.xp = gConfLevel[value-1].Xp;
                        player.markDirty('status.xp');
                    } else {
                        user.status[type] = value;
                        player.addStatusAwards([['user', type, value - oldValue]]);
                    }
                    player.markDirty('status.'+type); 
                } else {
                    resp.code = 1; resp.desc = 'way not support'; break;
                }
            } else {
                resp.code = 1; resp.desc = 'type not support'; break;
            }
        }else if( method == 'name' ) {
            var newName = req.args.value + "";
            user.info.un = newName;
            player.markDirty('info.un');
        }else if( method == 'mark' ) {
            if( !user.mark.hasOwnProperty(req.args.type) || isNaN(req.args.value) ) {
                resp.code = 1; resp.desc = 'type num not support'; break;
            }
            var type = req.args.type;
            var value = +req.args.value;
            if( value < 0 ) {
                resp.code = 1; resp.desc = 'invalid value'; break;
            }
            user.mark[type] = value;
            player.markDirty('mark.'+type);
        }else if( method == 'task' ) {
            if( !user.task.hasOwnProperty(req.args.type) ||
                isNaN(req.args.value) ) {
                resp.code = 1; resp.desc = 'type num not support'; break;
            }
            
            var type = req.args.type;
            var value = +req.args.value; 
            if( !gConfTask[value]) {
                resp.code = 1; resp.desc = 'value error'; break;
            }

            if( 'main' == type ) {
                if( value >= 1000 ) {
                    resp.code = 1; resp.desc = 'value error'; break;
                }

                user.task.main = {
                    'id' :value, 
                    'progress':{
                        '1':0,
                        '2':0,
                    },
                }

                player.markDirty('task.main');
            }else if( 'branch' == type ) {
                if( value < 1000 ) {
                    resp.code = 1; resp.desc = 'value error'; break;
                }

                user.task.branch = {
                    'id' :value, 
                    'progress':{
                        '1':0,
                        '2':0,
                    },
                }

                player.markDirty('task.branch');
            }  
        }else if( method == 'get' ) {
            resp.data = player.user;
        }else if( method == 'set_user' ){
            var user_ = req.args.value;
            if (!user_) {
                resp.code = 1; resp.desc = 'invalid args'; break;
            }
            user_ = JSON.parse(user_);
            if (!config.AllowSetUser) {
                resp.code = 1; resp.desc = 'not allow'; break;
            }
            user_._id = player.uid;
            for (var _key in user_) {
                if (user_.hasOwnProperty(_key)) {
                    player.user[_key] = user_[_key];
                }
            }
            gDBUser.save(player.user, function(err, result) {
                if( err ) {
                    ERROR(util.format('%d SAVE %j', player.uid, err));
                }else {
                    player.cleanDirty();
                    LOG(util.format('%d SAVE %j', player.uid, player.user));
                }
                onHandled();
            }.bind(this));
            return;
        }else if( method == 'vip' ) {
            if( isNaN(req.args.value) ) {
                resp.code = 1; resp.desc = 'type num not support'; break;
            }
            var value = Math.round(req.args.value);
            if( value < 0 || value > 10) {
                resp.code = 1; resp.desc = 'invalid value'; break;
            }

            user.status.vip = value;
            if( !gConfVip[value] ) {
                resp.code = 1; resp.desc = 'invalid value '; break;
            }

            user.activity.paid = gConfVip[value].Cash;
            player.markDirty('status.vip');
            player.markDirty('activity.paid');
        }else if( method == 'block' ){
            gPlayers.unload(req.uid);
        }else if( method == 'block_talk' ){
            user.activity.block_talk = 1;
            player.markDirty('activity.block_talk');
        } else if( method == 'unblock_talk' ){
            user.activity.block_talk = 0;
            player.markDirty('activity.block_talk');
        } else if (method == 'unblock_limit') {
            player.setDailyVar('except_score', 0);
            player.setDailyVar('login_times', 0);
        }else if( method == 'inventory'){
            // 发放material/gem
            var type = req.args.type;
            if( type == 'material' || type == 'gem' ) {
                var conf = null;
                if( type == 'gem' ) {
                    conf = gConfGem[req.args.id];
                }else if( type == 'material' ) {
                    conf = gConfMaterial[req.args.id];
                }
                if( !conf ) {
                    resp.code = 1; resp.desc = 'invalid id'; break;
                }
                var id = req.args.id;

                if( isNaN(req.args.num) || Math.round(req.args.num) <= 0 ) {
                    resp.code = 1; resp.desc = 'invalid num'; break;
                }
                var num = Math.round(req.args.num)
                if( num > 1000 ) {
                    resp.code = 1; resp.desc = 'num too large, please less than 1000'; break;
                }

                player.addStatusAwards(player.addAwards([[type, id, num]]));
            }else{
                resp.code = 1; resp.desc = 'not material or gem'; break;
            }
        }else if( method == 'equip'){
            var type = req.args.type;
            var level = req.args.level;
            if( type != 'magic' && type != 'weapon' && type != 'accessory' && type != 'armor' ){
                resp.code = 1; resp.desc = 'invalid type'; break;
            }
            if( isNaN(req.args.level) || !gConfEquip[req.args.level]) {
                resp.code = 1; resp.desc = 'invalid level'; break;
            }

            player.addStatusAwards(player.addAwards([['equip', type, +req.args.level, 1]]));
        }else if( method == 'role'){
            if( isNaN(req.args.id) || !gConfRole[req.args.id] ) {
                resp.code = 1; resp.desc = 'invalid id'; break;
            }
            if( isNaN(req.args.num) || +req.args.num <= 0  || req.args.num >= 10000 ) {
                resp.code = 1; resp.desc = 'invalid num'; break;
            }

            var rid = +req.args.id;
            var num = Math.round(req.args.num);
            
            player.addStatusAwards(player.addAwards([['role', rid, num]]));
        } else if (method == 'userrole') {
            if (isNaN(req.args.id)) {
                 resp.code = 1; resp.desc = 'invalid id field'; break;
            }

            var roleId = req.args.id;
            var roleConf = gConfRole[roleId];
            if (!roleConf) {
                resp.code = 1; resp.desc = 'invalid role id'; break;
            }

            var changeType = req.args.type;
            var changeValue = parseInt(req.args.value);
            var role = user.role[roleId];

            if (!role) {
                resp.code = 1; resp.desc = 'user role not found'; break;
            }

            if ('level' == changeType) {
                if (changeValue > user.status.level) {
                    resp.code = 1; resp.desc = 'role level wrong'; break;
                }

                if(!gConfRoleLevel[changeValue - 1]) {
                    resp.code = 1; resp.desc = 'role level invalid'; break;
                }

                role.level = changeValue;
                role.xp = gConfRoleLevel[changeValue - 1].Xp;
                player.markDirty('role.'+roleId+'.level');
                player.markDirty('role.'+roleId+'.xp');
            } else if ('grouth' == changeType) {
                doChangeRoleGrouth(player, role, changeValue);
            } else if ('soul' == changeType) {
                if(roleConf.Quantity != 'orange') {
                    resp.code = 1; resp.desc = 'user role is not orange'; break;  
                }
                doChangeRoleSoul(player, role, changeValue);
            } else if ('god' == changeType) {
                if(user.status.level < gConfGlobal.AwakeOpenLevelLimit) {
                    resp.code = 1; resp.desc = 'user level not reach'; break;
                }

                if(!roleConf['GodUrl'+changeValue]) {
                    resp.code = 1; resp.desc = 'can not awake'; break;
                }

                doChangeRoleGod(player, role, changeValue);
            }
        } else if( method == 'clear_inventory'){
            player.user.inventory.gem = {};
            player.user.inventory.material = {};
            player.user.role_card = {};

            player.markDirty('inventory');
            player.markDirty('role_card');
        }else if( method == 'message'){
            var ims = [];
            var item = gMessage.imHead;
            for( var i=0; i<30 && item.next; i++ ) {
                ims.push(item.next.obj);
                item = item.next;
            }
            resp.data.ims = ims;
        } else if ( method == 'league' ) {
            if (isNaN(req.args.value)) {
                resp.code = 1; resp.desc = 'invalid value field'; break;
            }

            var type = req.args.type;
            var value = parseInt(req.args.value);

            if ('gradexp' == type) {
                player.addGradeXp(value);
            } else {
                var worldReq = {
                    mod : 'league',
                    act : 'gm_change',
                    args : {
                        'key' : req.args.key,
                        'name' : req.args.name,
                        'type' : type,
                        'value' : value,
                    },
                }
                requestWorld(worldReq, resp, function() {
                    onHandled();
                });
                return;
            }
        } else if ('other' == method) {
            var command = req.args.command;
            if ('smashlandReset' == command) {
                player.smashLandReset();
            } else if ('addCloudShopBuys' == command) {
                var value = parseInt(req.args.value);
                var cloudReq = {
                    mod: 'cloudshop',
                    act: 'addBuys',
                    uid: uid,
                    args: {
                        value: value,
                    }
                }
                requestCloud(cloudReq, resp, function() {
                    onHandled();
                });
                return
            } else {
                resp.code = 1; resp.desc = 'command not support'; break;
            }
        } else if('add_cash' == method){
            var numToAdd = +req.args.value;
            if (isNaN(numToAdd)) {
                resp.code = 1; resp.desc = 'invalid argments'; break;
            } else {
                if (player.alterResource("cash", numToAdd)) {
                    player.addStatusAwards([['user', 'cash', numToAdd]]);
                    resp.code = 0; resp.desc = 'ok'; break;
                } else {
                    resp.code = 1; resp.desc = 'failed'; break;
                }
            }
        } else if ('autoStrong' == method) { //一键升级武将
            //更新玩家信息
            var autoLevel = 120;
            var autoVip = 6;
            var autoCash = 99999;

            if (user.status.level < autoLevel) {
                doChangePlayerLevel(player, autoLevel);
            }

            if (!user.status.vip || user.status.vip < autoVip) {
                user.status.vip = autoVip;
                player.markDirty('status.vip');
            }

            if (user.status.cash < autoCash) {
                user.status.cash = autoCash;
                player.markDirty('status.cash');
            }

            if (!user.info.un) {
                user.info.un = req.openid;
                player.markDirty('info.un');
            }

            //升级神兽
            var pet = user.pet;
            pet.level = 1;
            for (var level in gConfPet) {
                var petConf = gConfPet[level];
                if (pet.level > +level) {
                    continue;
                }

                pet.level = +level;
                var newSkill = petConf.Skill1;
                if( newSkill && pet.skills.indexOf(newSkill) < 0 ) {
                    pet.skills.push(newSkill);
                    pet.skill_levels[newSkill] = 1;
                }
                
                var newPassiveSkill = petConf.Skill2;
                if( newPassiveSkill ) {
                    pet.skill_levels[newPassiveSkill] = 1;
                }

                player.markDirty('pet.level');
                player.markDirty('pet.skills');
                player.markDirty('pet.skill_levels');
            }
            player.checkEvent('PetLevel');
            
            //自动添加武将
            var autoRoleArr = [1, 2, 3, 12, 13, 23, 48, 279, 280, 281, 282, 300, 301, 302, 303];
            var autoGodLevel = 3;
            var autoWingLevel = 15;
            var autoStarLevel = 4;
            autoRoleArr.forEach(function (rid) {
                var roleConf = gConfRole[rid];
                if (!roleConf) {
                    return;
                }

                player.addRole(rid);
                var role = user.role[rid];
                if (!role) {
                    return;
                }

                if (role.level < user.status.level) {
                    role.level = user.status.level;
                    role.xp = gConfRoleLevel[user.status.level - 1].Xp;
                    player.markDirty(util.format('role.%d.level', rid));
                    player.markDirty(util.format('role.%d.xp', rid));
                }

                if(roleConf['GodUrl'+autoGodLevel]) {
                    doChangeRoleGod(player, role, autoGodLevel);
                }

                if (!role.wing || role.wing < autoWingLevel) {
                    role.wing = autoWingLevel;
                    player.markDirty(util.format('role.%d.wing', rid));
                }

                if (!role.star || role.star < autoStarLevel) {
                    role.star = autoStarLevel;
                    player.markDirty(util.format('role.%d.star', rid));
                }

                role.skill = 3;
                player.markDirty(util.format('role.%d.skill', rid));
            });
        } else {
            resp.code = 1; resp.desc = 'method not support'; break;
        }
    } while(false);
    onHandled();
}

exports.pay = function(player, req, resp, onHandled) {
    var user = player.user;
    do{
        if( req.args.key != config.GMAuth || isNaN(req.args.cash) ) {
            resp.code = 1; resp.desc = 'invalid key or cash'; break;
        }

        var cash = +req.args.cash;
        if( cash <= 0 || cash >= 10000000 ) {
            resp.code = 1; resp.desc = 'invalid cash'; break;
        }

        var paySN  = req.args.billno;
        var payAmt = +req.args.amt || 0;
        if (paySN) {
            //Recharge|iEventId|dtEventTime|iWorldId|iSource|iSrcUin|iUin|iRoleId|vRoleName|vClientIp|vReMarks|iPayBefore|iPayDelta|iPayAfter|vDesc|iLoginWay
            writeRecord(util.format('Recharge|pay|%s|%d|0|0|%s|%d|RoleName|%s|%s|%d|%d|%d|pay|0',
                Date.stdFormatedString(), config.ServerId, player.openid, player.uid,
                player.clientIP, paySN, user.status.cash, payAmt, user.status.cash+cash));
        }

        var activity = user.activity;
        // 本服新首充
        var newFirstPayCount = Object.keys(activity.new_first_pay).length;
        if( newFirstPayCount < Object.keys(gConfAvNewFirstPay).length ) {
            var rewardCashs = Object.keys(gConfAvNewFirstPay);
            rewardCashs.sort(function(a, b) { return a - b; });
            var rewardCash = +rewardCashs[newFirstPayCount];
            if( rewardCash && (cash >= rewardCash)  ) {
                activity.new_first_pay[rewardCash] = 0;
                player.markDirty(util.format('activity.new_first_pay.%d', rewardCash));
            }
        }

        player.pay(cash);
        var now = common.getTime();
        
        // 每日首充
        if (player.dailyPayIsOpen()) {
            player.updateDailyPay();

            var today = common.getDate();
            var dailyPay = user.daily_pay;
            dailyPay.cash += cash;
            if( dailyPay.cash >= gConfGlobal.DailyPayCashMin && (dailyPay.month_day != today) ) {
                player.updateDailyPayMonth();

                dailyPay.month_pay += 1;
                dailyPay.month_day = today;
            }
            player.markDirty('daily_pay');
        }
       
        // 充值嘉年华
        player.addPayCarnivalCash(cash);

        // 每日变量-今日充值
        player.addDailyVar('pay_cash', cash, true);
        
        // 充值特惠
        var activitySchedule = findActivitySchedule('charge');
        if( activitySchedule ) {
            if( activity.charge.time != activitySchedule.time ) {
                activity.charge = {
                    'cash': cash,
                    'time': activitySchedule.time,
                    'got' : {
                    },
                };
                player.markDirty('activity.charge');
            }else{
                activity.charge.cash += cash;
                player.markDirty('activity.charge.cash');
            }
        }
        
        // 新服充值特惠
        activitySchedule = findActivitySchedule('newcharge');
        if( activitySchedule ) {
            if( activity.new_charge.time != activitySchedule.time ) {
                activity.new_charge = {
                    'cash': cash,
                    'time': activitySchedule.time,
                    'got' : {
                    },
                };
                player.markDirty('activity.new_charge');
            }else{
                activity.new_charge.cash += cash;
                player.markDirty('activity.new_charge.cash');
            }
        }
        
        // 充值回馈
        activitySchedule = findActivitySchedule('chargefeed');
        if( activitySchedule ) {
            if( activity.charge_feed.time != activitySchedule.time ) {
                activity.charge_feed = {
                    'score': cash * gConfGlobal.PayScorePerCash,
                    'time': activitySchedule.time,
                    'cost' : 0,
                    'exchange' : 0,
                    'got' : {},
                };
                player.markDirty('activity.charge_feed');
            }else{
                activity.charge_feed.score += cash * gConfGlobal.PayScorePerCash;
                player.markDirty('activity.charge_feed.score');
            }
        }

        // 充值土豪
        /*
        activitiesConf = gConfActivities.gentry;
        if( activitiesConf ) {
            if( activity.gentry.time != activitiesConf.StartTime ) {
                activity.gentry = {
                    'cash': 0,          
                    'time': activitiesConf.StartTime,
                    'got' : 0,
                };
                player.markDirty('activity.gentry');
            }

            if( (now >= activitiesConf.StartTime - 20) && (now <= activitiesConf.EndTime + 20) ) {
                activity.gentry.cash += cash;
                player.markDirty('activity.gentry.cash');
            }
        }
        */

        // 充值排行
        activitySchedule = findActivitySchedule('payrank');
        if( activitySchedule ) {
            if( activity.pay_rank.time != activitySchedule.time ) {
                activity.pay_rank = {
                    'time' : activitySchedule.time,
                    'paid' : {},
                    'got' : {},
                };
                player.markDirty('activity.pay_rank');
            }
            var day = common.getDayPassed(activitySchedule.time);
            var pay_rank = activity.pay_rank;
            if( !pay_rank.paid[day] ) {
                pay_rank.paid[day] = 0;
            }

            pay_rank.paid[day] += cash;
            player.markDirty('activity.pay_rank.paid');

            var totalPaid = 0;
            for( var paidDay in pay_rank.paid ) {
                totalPaid += pay_rank.paid[paidDay];
            }

            if (totalPaid >= gConfAvPayRank[activitySchedule.conf].CashMin) {
                // 更新充值排行榜
                var worldReq = {
                    uid: req.uid,
                    mod: 'activity',
                    act: 'update_payrank',
                    args: {
                        'conf': activitySchedule.conf,
                        'paid': totalPaid
                    }
                };

                var worldResp = { };
                requestWorld(worldReq, worldResp);
            }
        }

        // 每日充值排行
        activitySchedule = findActivitySchedule('dailypayrank');
        if( activitySchedule ) {
            if( activity.daily_pay_rank.time != activitySchedule.time ) {
                activity.daily_pay_rank = {
                    'time' : activitySchedule.time,
                    'paid' : {},
                };
                player.markDirty('activity.daily_pay_rank');
            }

            var day = common.getDayPassed(activitySchedule.time);
            var dailyPayRank = activity.daily_pay_rank.paid;
            if( !dailyPayRank[day] ) {
                dailyPayRank[day] = 0;
            }
            dailyPayRank[day] += cash;
            player.markDirty('activity.daily_pay_rank.paid');

            if( dailyPayRank[day] >= gConfAvDailyPayRank[activitySchedule.conf].CashMin) {
                // 更新充值排行榜
                var worldReq = {
                    uid: req.uid,
                    mod: 'activity',
                    act: 'update_daily_payrank',
                    args: {
                        'conf': activitySchedule.conf,
                        'day': day,
                        'paid': dailyPayRank[day]
                    }
                };

                var worldResp = { };
                requestWorld(worldReq, worldResp);
            }
        }

        // 充值神将
        var activitySchedule = findActivitySchedule('chargerole');
        if( activitySchedule ) {
            if( activity.charge_role.time != activitySchedule.time ) {
                activity.charge_role = {
                    'cash': cash,
                    'time': activitySchedule.time,
                    'got' : {
                    },
                };
                player.markDirty('activity.charge_role');
            }else{
                activity.charge_role.cash += cash;
                player.markDirty('activity.charge_role.cash');
            }
        }

        // 充值限量
        var activitySchedule = findActivitySchedule('chargelimit');
        if( activitySchedule ) {
            if( activity.charge_limit.time != activitySchedule.time ) {
                activity.charge_limit = {
                    'cash': cash,
                    'time': activitySchedule.time,
                    'got' : {
                    },
                    'buy' : {
                    },
                };
                player.markDirty('activity.charge_limit');
            }else{
                activity.charge_limit.cash += cash;
                player.markDirty('activity.charge_limit.cash');
            }
        }

        // 充值全民觉醒限量
        var activitySchedule = findActivitySchedule('chargegod');
        if( activitySchedule ) {
            if( activity.chargegod_limit.time != activitySchedule.time ) {
                activity.chargegod_limit = {
                    'cash': cash,
                    'time': activitySchedule.time,
                    'got' : {
                    },
                    'buy' : {
                    },
                };
                player.markDirty('activity.chargegod_limit');
            }else{
                activity.chargegod_limit.cash += cash;
                player.markDirty('activity.chargegod_limit.cash');
            }
        }

        // 充值全民2-跨服充值排行
        var activitySchedule = findActivitySchedule('serverpayrank');
        if( activitySchedule ) {
            if( activity.server_payrank.time != activitySchedule.time ) {
                activity.server_payrank = {
                    'cash': cash,
                    'time': activitySchedule.time,
                    'reward': {},
                };
                player.markDirty('activity.server_payrank');
            }else{
                activity.server_payrank.cash += cash;
                player.markDirty('activity.server_payrank.cash');
            }
            
            if( activity.server_payrank.cash >= gConfGlobal.ServerPayRankCashMin ) {
                // 更新充值排行榜
                var cloudReq = {
                    uid: req.uid,
                    mod: 'activity',
                    act: 'update_server_payrank',
                    args: {
                        'time': activitySchedule.time,
                        'server': config.ServerId - 1,
                        'paid': activity.server_payrank.cash, 
                        'name': user.info.un,
                    }
                };

                var cloudResp = { };
                requestCloud(cloudReq, cloudResp);
            }
        }
        
        var today = common.getDate()

        // 充值土豪送礼
        var activitySchedule = findActivitySchedule('richsend');
        if( activitySchedule ) {
            if( activity.rich_send.time != activitySchedule.time ) {
                activity.rich_send = {
                    'cash': cash,
                    'time': activitySchedule.time,
                    'day': common.getDate(),
                    'reward': {},
                };
                player.markDirty('activity.rich_send');
            }else{
                activity.rich_send.cash += cash;
                player.markDirty('activity.rich_send.cash');
            }
            
            var worldReq = {
                uid: req.uid,
                mod: 'activity',
                act: 'update_richsend',
                args: {
                    'cash': cash,
                }
            };

            if( activity.rich_send.cash >= gConfGlobal.RichSendRankCashMin ) {
                worldReq.args.paid = activity.rich_send.cash;
            }

            var worldResp = { };
            requestWorld(worldReq, worldResp);
        }

        // 全民福利
        var activitySchedule = findActivitySchedule('allgift');
        var activitiesConf = gConfActivities.allgift;
        if( activitySchedule && activitySchedule.conf 
            && (player.user.status.level >= activitiesConf.OpenLevel) ) {

            var confId = activitySchedule.conf;
            var activityDayPassed = common.getDayPassed( activitySchedule.time );
            var avAllGiftConf = ( gConfAvAllGift[confId] ? gConfAvAllGift[confId][activityDayPassed] : null );
            if( avAllGiftConf ) { 
                var allGift = activity.all_gift;
                if( allGift.time == activitySchedule.time ) {
                    if( allGift.day != today ) {
                        allGift.paid = cash;
                        allGift.day = today;
                        allGift.got = {
                            'all' : 0,
                            'self' : 0,
                        };
                        player.markDirty('activity.all_gift');
                    }else {
                        allGift.paid += cash;
                        player.markDirty('activity.all_gift.paid');
                    }
                }else{
                    allGift = {
                        'paid': cash,
                        'time': activitySchedule.time,
                        'day': common.getDate(),
                        'got': {
                            'all' : 0,
                            'self' : 0,
                        },
                    };

                    activity.all_gift = allGift;
                    player.markDirty('activity.all_gift');
                }
                
                var worldReq = {
                    uid: req.uid,
                    mod: 'activity',
                    act: 'update_all_gift',
                    args: {
                        'cash': cash,
                    }
                };

                var payMin = ( avAllGiftConf['self'] ? avAllGiftConf['self']['PayMin'] : 0 );

                if( payMin && allGift.paid >= payMin ) { 
                    worldReq.args.paid = allGift.paid;
                }

                var worldResp = { };
                requestWorld(worldReq, worldResp);
            }
        }

        // 全民充值 
        activitySchedule = findActivitySchedule('allcharge');
        if( activitySchedule ) {
            if( activity.all_charge.time != activitySchedule.time ) {
                activity.all_charge =  {
                    'cash' : 0,
                    'time' : activitySchedule.time,
                    'got' : {},
                };

                player.markDirty('activity.all_charge');
            }

            activity.all_charge.cash += cash;
            player.markDirty('activity.all_charge.cash');
            var allChargeCash = activity.all_charge.cash;
            
            var isReach = false;
            for( var id in gConfAvAllCharge ) {
                if( allChargeCash >= gConfAvAllCharge[id].CashMin ) {
                    isReach = true;
                    break; 
                }
            }

            if( isReach ) {
                // 更新充值人数
                var worldReq = {
                    uid: req.uid,
                    mod: 'activity',
                    act: 'update_all_charge',
                    args: {
                        'cash': allChargeCash,
                    }
                };

                var worldResp = { };
                requestWorld(worldReq, worldResp);
            }
        }

        //充值幸运转
        player.addActivityValue('luckycharge', 'score', cash*gConfGlobal.LuckyChargeScoreRatio);
        // 日积月累
        player.addActivityValue('daymonthpay', 'cash', cash);

        // 春节每日首充
        var activityNewYearFirstPay = player.getActivity('newyearfirstpay');
        if (activityNewYearFirstPay && !activityNewYearFirstPay.cash) {
            activityNewYearFirstPay.cash = cash;
            player.saveActivityValue('newyearfirstpay', 'cash');
        }

        player.alterResource('cash', cash, payAmt, paySN);

        resp.data.pf = player.user.info.platform;
        resp.data.ip = user.mark.lastIP || player.clientIP;
    }while(false);

    onHandled();
}

exports.yellow_first = function(player, req, resp, onHandled) {
    do{
        if( req.args.key != config.GMAuth ) {
            resp.code = 1; resp.desc = 'invalid key'; break;
        }

        var user = player.user;

        var color = req.args.is_blue ? 'blue_first' : 'yellow_first';

        if( user.activity[color] ) {
            resp.code = 1; resp.desc = 'got'; break;
        }

        user.activity[color] = 1;

        user.status.gold += 500000;
        user.status.soul += 1000;

        player.markDirty('activity.'+color);
        player.markDirty('status.gold');
        player.markDirty('status.soul');

        resp.data.gold = 500000;
        resp.data.soul = 1000;

    }while(false);

    onHandled();
}

exports.yellow_daily = function(player, req, resp, onHandled) {
    do{
        if( req.args.key != config.GMAuth || isNaN(req.args.level) ) {
            resp.code = 1; resp.desc = 'invalid key or level'; break;
        }
        
        var level = +req.args.level;
        var user = player.user;

        var color = req.args.is_blue ? 'blue' : 'yellow';

        if( user.mark[color] ) {
            resp.code = 1; resp.desc = 'got'; break;
        }

        if( level <= 0 ) {
            resp.code = 1; resp.desc = 'invalid level'; break;
        }

        user.mark[color] = 1;
        var addFood = yellowDailyReward[level].food;
        var addGold = yellowDailyReward[level].gold;
        if( req.args.year ) {
            addGold += 20000;
        }

        if( req.args.super ) {
            addGold += 20000;
        }
        
        user.status.food += addFood; 
        user.status.gold += addGold;

        player.markDirty('status.food');
        player.markDirty('status.gold');
        player.markDirty('mark.'+color);

        resp.data.food = addFood;
        resp.data.gold = addGold;

    }while(false);

    onHandled();
}

exports.blue_level = function(player, req, resp, onHandled) {
    do{
        if( req.args.key != config.GMAuth || isNaN(req.args.level) ) {
            resp.code = 1; resp.desc = 'invalid key or level'; break;
        }
        
        var level = Math.floor(req.args.level);
        var user = player.user;

        if( (level % 10) != 0 || level > 80 || level < 10 ) {
            resp.code = 1; resp.desc = 'invalid level'; break;
        }

        if( user.status.level < level ) {
            resp.code = 1; resp.desc = 'level not reach'; break;
        }

        level = level/10;

        if( user.activity.blue_level & (1<<(level-1)) ) {
            resp.code = 1; resp.desc = 'got'; break;
        }

        user.activity.blue_level |= (1<<(level-1));

        var addGold = blueLevelGoldReward[level];
        user.status.gold += addGold;

        player.markDirty('status.gold');
        player.markDirty('activity.blue_level');

        resp.data.gold = addGold;

    }while(false);

    onHandled();
}

exports.query_cash = function(player, req, resp, onHandled) {
    do{
        if( req.args.key != config.GMAuth ) {
            resp.code = 1; resp.desc = 'invalid key'; break;
        }
        resp.data.cash = player.user.status.cash;    
    }while(false);

    onHandled();
}

exports.reset_task_v3 = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (req.args.key != config.GMAuth) {
            resp.code = 1; resp.desc = 'invalid key'; break;
        }

        var taskId = req.args.task_id;
        if (!taskId) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }
        
        var taskConf = gConfQQTask[taskId];
        if (!taskConf) {
            resp.code = 1; resp.desc = 'invalid task id'; break;
        }
        
        var activity = user.activity;
        if (activity.hasOwnProperty('contract_task_v3')) {
            activity.app_contract_id = taskId;
            activity.contract_task_v3 = 1;
            activity.contract_task_reward_v3 = 0;
            player.markDirty('activity.app_contract_id');
            player.markDirty('activity.contract_task_v3');
            player.markDirty('activity.contract_task_reward_v3');
        }

    } while (false);

    onHandled();
}

exports.task_v3 = function(player, req, resp, onHandled) {
    do{
/*
    check: 开发者仅需要查询任务步骤是否完成，返回步骤完成状态。
    check_award: 开发者需要查询任务步骤是否完成，若步骤已完成，直接给用户发货（payitem），并返回发货是否成功。
    award: 平台通知开发者直接给给用户发货，开发者返回发货是否成功。
*/
        if( req.args.key != config.GMAuth ) {
            resp.code = 1; resp.desc = 'invalid key'; break;
        }
        
        var user = player.user;
        if( !user.activity.hasOwnProperty('contract_task_v3') ) {
            resp.data.ret = 1; break;
        }

        var step = +req.args.step;
        var cmd = req.args.cmd;
        if ('check_award' == cmd) {
            if( user.activity.contract_task_reward_v3 >= step ) {
                // 领取过奖励了
                resp.data.ret = 3;
            } else if (!player.checkTaskV3Step(step)) {
                resp.data.ret = 2;
            } else {
                player.giveTaskV3Reward(step);
                resp.data.ret = 0;
            }
        } else if ('check' == cmd) {
            if( user.activity.contract_task_reward_v3 >= req.args.step ) {
                // 领取过奖励了
                resp.data.ret = 3;
            }else if(!player.checkTaskV3Step(step)) {
                resp.data.ret = 2;
            }else {
                resp.data.ret = 0;
            }
        } else if ('award' == cmd) {
            if (user.activity.contract_task_reward_v3 < step) {
                player.giveTaskV3Reward(step);
            }

            resp.data.ret = 0;
        }
    } while (false);

    onHandled();
}

exports.p3366_daily = function(player, req, resp, onHandled) {
    do{
        if( req.args.key != config.GMAuth || isNaN(req.args.level) ) {
            resp.code = 1; resp.desc = 'invalid key or level'; break;
        }
        
        var level = +req.args.level;
        var user = player.user;

        if( user.mark.p3366 ) {
            resp.code = 1; resp.desc = 'got'; break;
        }

        if( level <= 0 ) {
            resp.code = 1; resp.desc = 'invalid level'; break;
        }
        
        var gift = p3366Gifts[0];
        for( var i=0,max=p3366Gifts.length; i<=max; i++ ) {
            gift = p3366Gifts[i];
            if( gift.min <= level && gift.max >= level ) {
                break;
            }
        }

        var awards = player.addAwards(gift.awards);

        user.mark.p3366 = 1;
        player.markDirty('mark.p3366');

        resp.data.awards = awards;
    }while(false);

    onHandled();
}

exports.market_diamond = function(player, req, resp, onHandled) {
    do{
        if( req.args.key != config.GMAuth ) {
            resp.code = 1; resp.desc = 'invalid key'; break;
        }
        
        var user = player.user;
        var diamondActivity = user.activity.yellow_diamond;

        if( !diamondActivity ) {
            resp.code = 1; resp.desc = 'no activity'; break;
        }

        var activitiesConf = gConfActivities.yellowdiamond;
        var now = common.getTime();
        if( activitiesConf && (now >= activitiesConf.StartTime - 20) 
            && (now <= activitiesConf.EndTime + 20) ) {
            if( diamondActivity.opened < gConfGlobal.YellowDiamondLimit ) {
                player.addInventory('material', 66, 1);
            }

            diamondActivity.opened += 1;
            player.markDirty('activity.yellow_diamond');
        }

    }while(false);

    onHandled();
}

exports.get_user = function(player, req, resp, onHandled) {
    do{
        if( req.args.key != config.GMAuth ) {
            resp.code = 1; resp.desc = 'invalid key'; break;
        }

        var taskId = parseInt(req.args.task_id);
        // 台湾乐元素激励跳转预注册领取奖励接口
        var twRegisterPromotionArgs = req.args.tw_register_promotion || 0; 

        var user = player.user;
        
        var loginDays = user.mark.login_days;
        var lastLoginDay = user.mark.day;
        var today = common.getDate();

        var loginCount = 0;
        var loginCountActivitySchedule = findActivitySchedule('logincount');
        if( loginCountActivitySchedule) {
            if (taskId && user.activity.kaishui_promotion) {
                var task = {
                    1 : 6, // 玩家等级达到6级 
                };
                if ((taskId in task) && !user.activity.kaishui_promotion.task[taskId]) {
                    user.activity.kaishui_promotion.task[taskId] = 1; 
                    player.markDirty(util.format('activity.kaishui_promotion.task.%d', taskId));
                } 
            }
        }
        
        if( twRegisterPromotionArgs ) {
            var twPromotionActivitySchedule = findActivitySchedule('twregisterpromotion');
            if( twPromotionActivitySchedule ) {
                var twRegisterPromotion = user.activity.tw_register_promotion;
                if( !twRegisterPromotion || 
                    (twRegisterPromotion.time != twPromotionActivitySchedule.time) ) {
                    twRegisterPromotion = {
                        'got' : 0,
                        'time' : twPromotionActivitySchedule.time,
                    };

                    user.activity.tw_register_promotion = twRegisterPromotion;
                    player.markDirty('activity.tw_register_promotion');
                } 

                if( !twRegisterPromotion.got ) {
                    // 周一礼包
                    player.addAwards([[ 'material', '55', 5 ], [ 'material', '48', 20 ],[ 'user', 'gold', 200000 ]]);
                    twRegisterPromotion.got = 1;
                    player.markDirty('activity.tw_register_promotion');
                    resp.data.promotion_got = 1;
                }
            }
        }

        resp.data.login = loginDays ? 1 : 0;                        // 玩家是否登录过游戏
        resp.data.today_login = (lastLoginDay == today) ? 1 : 0;    // 今日是否登录游戏
        resp.data.login_days = loginDays;                           // 已经登陆天数
        resp.data.login_count = loginCount;                         // 活动期间已经登录天数
        resp.data.level = user.status.level;                        // 玩家等级
        resp.data.un = user.info.un;                                // 玩家名字

    }while(false);

    onHandled();
}

exports.bat_send = function(player, req, resp, onHandled) {
    var user = player.user;
    var resultArr = [];

    var itemsToSend = JSON.parse(req.items);
    for (var key in itemsToSend) {
        if (itemsToSend.hasOwnProperty(key)) {
            var itemToSend = itemsToSend[key];
            var result = null;
            var type = itemToSend[0];
            if (type == 'user') {
                result = _userStatus(itemToSend[1], +(itemToSend[2]));
            } else if (type == 'material' || type == 'gem') {
                result = _materialGem(type, +(itemToSend[1]), +(itemToSend[2]));
            } else if (type == 'card') {
                result = _card(+(itemToSend[1]), +(itemToSend[2]));
            } else {
                result = {'code':1, 'desc':'unsupport type'};
            }
            resultArr.push(result);
        }
    }

    // 返回操作结果
    resp.data = resp.data || {};
    resp.data.result = resultArr;

    onHandled();


    /**
     * 修改玩家基础数据
     * @param type
     * @param value
     * @returns {{code: number, desc: string}}
     * @private
     */
    function _userStatus(type, value) {
        LOG('_userStatus ' + type + " " + value);
        var resp = {'code':0, desc:''};
        do {

            if (user.status.hasOwnProperty(type)) {
                //if ('cash' == type) {
                //    resp.code = 1; resp.desc = 'status type forbidden'; break;
                //}

                if (isNaN(value)) {
                    resp.code = 1; resp.desc = 'value invalid'; break;
                }

                if (value > maxValue || value < 0) {
                    resp.code = 1; resp.desc = 'value wrong'; break;
                }

                if ('cash' == type) {
                    if (!player.alterResource('cash', value)) {
                        resp.code = 1; resp.desc = 'add cash failed'; break;
                    }
                } else {
                    var nowValue = (user.status[type] || 0) + value;
                    if ('xp' == type) {
                        player.addXp(value);
                    } else if ('level' == type) {
                        if (!gConfLevel[nowValue]) {
                            resp.code = 1; resp.desc = 'level wrong'; break;
                        }
                        user.status.xp = gConfLevel[nowValue-1].Xp;
                        user.status.level = nowValue;
                        player.markDirty('status.xp');
                    } else {
                        user.status[type] = nowValue;
                    }
                    player.markDirty('status.'+type);
                }

                //if ('xp' == type) {
                //    resp.code = 1; resp.desc = "can't set xp"; break;
                //} else if ('level' == type) {
                //    if (!gConfLevel[value]) {
                //        resp.code = 1; resp.desc = 'level wrong'; break;
                //    }
                //    user.status.level = value;
                //    user.status.xp = gConfLevel[value-1].Xp;
                //    player.markDirty('status.xp');
                //} else {
                //    user.status[type] = value;
                //}
                //player.markDirty('status.'+type);
            } else {
                resp.code = 1; resp.desc = 'type not support'; break;
            }
        } while (false);
        return resp;
    }

    /**
     * 发材料和宝石
     * @param type
     * @param id
     * @param num
     * @returns {{code: number, desc: string}}
     * @private
     */
    function _materialGem(type, id, num) {
        LOG('_materialGem ' + type + " " + id + " " + num);
        var resp = {'code':0, desc:''};
        do {
            if( type == 'material' || type == 'gem' ) {
                var conf = null;
                if( type == 'gem' ) {
                    conf = gConfGem[id];
                }else if( type == 'material' ) {
                    conf = gConfMaterial[id];
                }
                if( !conf ) {
                    resp.code = 1; resp.desc = 'invalid id'; break;
                }

                if( isNaN(num) || Math.round(num) <= 0 ) {
                    resp.code = 1; resp.desc = 'invalid num'; break;
                }

                num = Math.round(num)
                if( num > 1000 ) {
                    resp.code = 1; resp.desc = 'num too large, please less than 1000'; break;
                }
                player.addInventory(type, id, num);
            }
        } while (false);
        return resp;
    }

    /**
     * 发卡片
     * @param id
     * @param num
     * @returns {{code: number, desc: string}}
     * @private
     */
    function _card(id, num) {
        LOG('_card ' + id + " " + num);
        var resp = {'code':0, desc:''};
        do {
            if( isNaN(id) || !gConfRole[id] ) {
                resp.code = 1; resp.desc = 'invalid id'; break;
            }
            if( isNaN(num) || num <= 0  || num >= 10000 ) {
                resp.code = 1; resp.desc = 'invalid num'; break;
            }

            var rid = id;
            var num = Math.round(num);

            player.addRoleCard(rid, num);
        } while (false);
        return resp;
    }
};
